﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace RESTClient
{
    public class RESTClient
    {
        #region Members

        String m_strUsername;
        String m_strPassword;
        Version m_httpVersion;
        String m_strMediaType;
        String m_strContentType;

        #endregion

        #region Ctor / Dtor

        public RESTClient()
        {
            m_strUsername = String.Empty;
            m_strPassword = String.Empty;
            m_httpVersion = HttpVersion.Version10;
            m_strMediaType = "application/xml";
            m_strContentType = "application/xml";

            CertificateUtility.SetCertificatePolicy();
        }

        public RESTClient(String _strUsername, String _strPassword, Version _httpVersion, 
                          String _strMediaType, String _strContentType)
        {
            m_strUsername = _strUsername;
            m_strPassword = _strPassword;
            m_httpVersion = _httpVersion;
            m_strMediaType = _strMediaType;
            m_strContentType = _strContentType;

            CertificateUtility.SetCertificatePolicy();
        }

        #endregion

        #region Private Methods

        private HttpStatusCode PerformRESTRequest(String strHTTPAction, String strURI, String strReqBody, 
                                                 ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;
            try
            {
                HttpWebRequest createdRequest = this.CreateRequest(strHTTPAction, strURI, strReqBody);
                httpResponse = createdRequest.GetResponse() as HttpWebResponse;
                statusCode = httpResponse.StatusCode;
                httpResponse.Close();

                Trace.WriteLine("StatusCode: " + statusCode.ToString(), TraceEventType.Information.ToString());
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        private HttpStatusCode PerformBodilessRESTRequest(String strHTTPAction, String strURI, 
                                                         ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;
            try
            {
                HttpWebRequest createdRequest = this.CreateBodilessRequest(strHTTPAction, strURI);
                httpResponse = createdRequest.GetResponse() as HttpWebResponse;
                statusCode = httpResponse.StatusCode;
                httpResponse.Close();

                Trace.WriteLine("StatusCode: " + statusCode.ToString(), TraceEventType.Information.ToString());
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }
         
            return statusCode;
        }

        private HttpStatusCode PerformRESTRequest(String strHTTPAction, String strURI, String strReqBody,
                                                 ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;
            try
            {
                HttpWebRequest createdRequest = this.CreateRequest(strHTTPAction, strURI, strReqBody);
                HttpWebResponse httpResponse = createdRequest.GetResponse() as HttpWebResponse;
                statusCode = httpResponse.StatusCode;                
                
                Trace.WriteLine("StatusCode: " + statusCode.ToString(), TraceEventType.Information.ToString());

                strResponse = this.ResponseToString(httpResponse);
                httpResponse.Close();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        private HttpStatusCode PerformBodilessRESTRequest(String strHTTPAction, String strURI,
                                                         ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;
            try
            {
                HttpWebRequest createdRequest = this.CreateBodilessRequest(strHTTPAction, strURI);
                HttpWebResponse httpResponse = createdRequest.GetResponse() as HttpWebResponse;
                statusCode = httpResponse.StatusCode;                

                Trace.WriteLine("StatusCode: " + statusCode.ToString(), TraceEventType.Information.ToString());

                strResponse = this.ResponseToString(httpResponse);
                httpResponse.Close();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        private HttpWebRequest CreateRequest(String strHTTPAction, String strURI, String strReqBody)
        {
            HttpWebRequest createdRequest = this.CreateBodilessRequest(strHTTPAction, strURI);
            this.SetRequestBody(ref createdRequest, strReqBody);
            
            return createdRequest;
        }

        private HttpWebRequest CreateBodilessRequest(String strHTTPAction, String strURI)
        {
            HttpWebRequest httpRequest = WebRequest.Create(strURI) as HttpWebRequest;
            httpRequest.Method = strHTTPAction;

            this.InitializeRequest(ref httpRequest);

            return httpRequest;
        }

        private void InitializeRequest(ref HttpWebRequest httpRequest)
        {
            if (!String.IsNullOrEmpty(m_strUsername) && !String.IsNullOrEmpty(m_strPassword))
            {
                httpRequest.Credentials = new NetworkCredential(m_strUsername, m_strPassword);
            }
            
            httpRequest.ProtocolVersion = m_httpVersion;
            httpRequest.MediaType = m_strMediaType;
            httpRequest.ContentType = m_strContentType;
        }

        private void SetRequestBody(ref HttpWebRequest httpRequest, String strReqBody)
        {
            if (strReqBody.Length > 0)
            {
                Stream requestStream = httpRequest.GetRequestStream();
                StreamWriter writer = new StreamWriter(requestStream);
                writer.Write(strReqBody);
                writer.Dispose();

                if (requestStream != null)
                {
                    requestStream.Dispose();
                }
            }
        }

        private String ResponseToString(HttpWebResponse httpResponse)
        {
            Stream responseStream = httpResponse.GetResponseStream();
            StreamReader responseReader = new StreamReader(responseStream);
            String strResponse = responseReader.ReadToEnd().Trim();
            
            responseReader.Dispose();            
            responseStream.Dispose();

            return strResponse;
        }        

        #endregion

        #region Public Methods

        public HttpStatusCode RequestGET(String strURI, ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("GET URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("GET", strURI, ref httpResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestGET(String strURI, ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("GET URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("GET", strURI, ref strResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestPUT(String strURI, String strReqBody, ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("PUT URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformRESTRequest("PUT", strURI, strReqBody, ref httpResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestPUT(String strURI, String strReqBody, ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("PUT URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformRESTRequest("PUT", strURI, strReqBody, ref strResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestPOST(String strURI, String strReqBody, ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("POST URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformRESTRequest("POST", strURI, strReqBody, ref httpResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestPOST(String strURI, String strReqBody, ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("POST URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformRESTRequest("POST", strURI, strReqBody, ref strResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestDELETE(String strURI, ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("DELETE URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("DELETE", strURI, ref httpResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestDELETE(String strURI, ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("DELETE URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("DELETE", strURI, ref strResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestHEAD(String strURI, ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("HEAD URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("HEAD", strURI, ref httpResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestHEAD(String strURI, ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("HEAD URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("HEAD", strURI, ref strResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestOPTIONS(String strURI, ref HttpWebResponse httpResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("OPTIONS URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("OPTIONS", strURI, ref httpResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        public HttpStatusCode RequestOPTIONS(String strURI, ref String strResponse)
        {
            HttpStatusCode statusCode = HttpStatusCode.SeeOther;

            try
            {
                Trace.WriteLine("OPTIONS URI: " + strURI, TraceEventType.Information.ToString());
                statusCode = this.PerformBodilessRESTRequest("OPTIONS", strURI, ref strResponse);
            }
            catch (System.Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceEventType.Error.ToString());
            }

            return statusCode;
        }

        #endregion
    }
}
